/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package MetricsRetriever.RetrieverComponents;

import DataStructures.ProjectInformation;
import DataStructures.RepositoryData;
import General.FileManager;
import General.Globals;
import JavaMetrics.BasicFileInfo;
import JavaMetrics.CommonCounter;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.*;
import org.tmatesoft.svn.core.wc.*;

/**
 *
 * @author Manuel
 */
public class SVNManager implements RepositoryManager{

    private ProjectInformation info;
    private SVNClientManager manager;
    private FileManager fManager;
    private RepositoryData repoData;

    public SVNManager(ProjectInformation i,FileManager fm){
        info = i;
        manager = SVNClientManager.newInstance();
        fManager = fm;
        repoData = new RepositoryData();
    }

    public RepositoryData getAllRepositoryData() {
        ArrayList<String> fileList = null;
        repoData = new RepositoryData();
        boolean checkedOut = false;
        boolean logged = false;
        String link = info.getRepositoryLink();
        if(link == null || link.isEmpty())
            return null;

        checkedOut = this.checkout(link, Globals.DATA_DIRECTORY+"/"+info.getName()+"/source");
        ArrayList log = this.getHistory(link, -1);
        if(log != null){
            repoData.setRepositoryHistory(log);
            logged = true;
        }
        try {
            manager.getWCClient().doCleanup(new File(Globals.DATA_DIRECTORY + "/" + info.getName() + "/source"));
        } catch (SVNException ex) {
        }

        if(checkedOut && logged){
            fileList= fManager.process(Globals.DATA_DIRECTORY+"/"+info.getName()+"/source");
            if(fileList.size()<10)
                return null;
            //repoData.setLOCs(fileList);
            //repoData.setOtherMetric(this.getOtherMetric
        }
         else
             return null;
        try {
            manager.getWCClient().doCleanup(new File(Globals.DATA_DIRECTORY + "/" + info.getName() + "/source"));
        } catch (SVNException ex) {
        }

        this.assessMetrics(fileList);

        return repoData;
    }


    private void assessMetrics(ArrayList<String> files) {
        if(files != null){
            repoData.setNoOfClasses(files.size());
            CommonCounter counter = new CommonCounter();
            BasicFileInfo fileInfo= null;
            long totalLinesOfCode = 0;
            for (int i = 0;i<files.size();i++){
                try{
                    fileInfo= counter.countlines(new File(files.get(i)));
                    totalLinesOfCode += fileInfo.getFsourcelines();
                }catch(NullPointerException ex){
                    repoData.setNoOfClasses(repoData.getNoOfClasses()-1);
                }
            }
            repoData.setLocs(totalLinesOfCode);
        }
    }





    //SVN SUPPORT


    private boolean checkout(String url, String destination){
        boolean success = false;
        int counter = 0;
        while(!success && counter<3){
            counter++;
            this.setupSVN();
            try {
                File destFile = new File(destination);
                if (!destFile.exists() || !destFile.isDirectory()) {
                    destFile.mkdirs();
                }
                //check out in a different thread, to timeout after 2h
                final SVNUpdateClient updateClient = manager.getUpdateClient();
                final File dFile = destFile;
                final String svnurl = url;
                long finishtime = System.currentTimeMillis() + (2 * 60 * 60 * 1000);
                Thread t = new Thread(new Runnable(){
                    public void run() {
                        try {
                            updateClient.doCheckout(SVNURL.parseURIEncoded(svnurl), dFile, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNDepth.INFINITY, false);
                        } catch (SVNException ex) {
                        }
                    }
                }
                );
                t.start();
                while(t.isAlive() && (System.currentTimeMillis() < finishtime)){
                    try {
                        Thread.sleep(10000l);
                    } catch (InterruptedException ex) {
                    }
                }
                if(t.isAlive()){
                    t.stop();
                    return false;
                }

                success = true;
                manager.getWCClient().doCleanup(destFile);
            } catch (Exception ex) {
            }
        }
        return success;
    }

    private ArrayList getHistory(String url, int maxEntries){
        this.setupSVN();
        ArrayList<SVNLogEntry> logEntries = null;
        maxEntries--;
        try {
            SVNRevision.HEAD.getNumber();
            SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
            repository.setAuthenticationManager(SVNWCUtil.createDefaultAuthenticationManager());
            long endRevision = SVNRevision.HEAD.getNumber();
            long startRevision = endRevision - maxEntries;
            if(maxEntries < 0 || startRevision < 0)
                startRevision = 0;
            Collection e = repository.log(new String[]{""}, null, startRevision, endRevision, true, true);
            logEntries = new ArrayList<SVNLogEntry>(e);
        } catch (Exception ex) {
            System.out.println("COULD NOT GET HISTORY OF "+info.getName()+" WITH GIVEN LINK "+url);
            return null;
        }
        SVNLogEntry head = (SVNLogEntry) logEntries.get(logEntries.size()-1);
        if(head.getDate() == null){
            head = (SVNLogEntry) logEntries.get(logEntries.size()-2);
        }
        info.setLastRelease(head.getDate());
        return logEntries;

    }

     private void setupSVN(){

         DAVRepositoryFactory.setup();
         //svn://, svn+xxx:// (svn+ssh:// in particular)
         SVNRepositoryFactoryImpl.setup();
         //file:///
         FSRepositoryFactory.setup();
    }





}

